package org.akomantoso.core.data;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.akomantoso.core.data.group.DocumentType;
import org.akomantoso.core.io.Externalizable;
import org.akomantoso.core.io.Input;
import org.akomantoso.core.io.InputConstants;
import org.akomantoso.core.io.Output;
import org.akomantoso.core.io.util.group.DocumentTypeGroup;

/**
 * The element akomaNtoso is the root element of all document types in Akoma Ntoso. It follows the pattern Universal
 * Root (http://www.xmlpatterns.com/UniversalRootMain.shtml)
 * 
 * <pre>
 * <xsd:element name="akomaNtoso">
 * 		<xsd:complexType>
 * 		    <xsd:sequence>
 * 			      <xsd:sequence>
 * 				        <xsd:group ref="documentType"/>
 * 			      </xsd:sequence>
 * 			      <xsd:element ref="components" minOccurs="0" maxOccurs="1"/>
 * 		    </xsd:sequence>
 *		</xsd:complexType>
 * </xsd:element>
 * </pre>
 * 
 * @author <a href="mailto:jacques.militello@gmail.com">Jacques Militello</a>
 * 
 * @since http://www.akomantoso.org/1.0
 */

public final class AkomaNtoso implements Externalizable{
 
	public static final String ELEMENT = "akomaNtoso";
	
	public static final String ELEMENT_COMPONENTS = "components";
	
	private DocumentType _documentType;
	
	private List<Component> _components;
	
	private final Map<String,String> _namespaces = new HashMap<String, String>(6);
	
	public DocumentType getDocumentType() {
		return _documentType;
	}
	public void setDocumentType(DocumentType documentType) {
		_documentType = documentType;
	}
	
	public List<Component> getComponents() {
		return _components;
	}
	
	public void addComponent(Component component) {
		if (_components == null) {
			_components = new ArrayList<Component>(4);
		}
		_components.add(component);
	}
	

	/**
	 * @see org.akomantoso.core.io.Externalizable#writeExternal(org.akomantoso.core.io.Output)
	 */
	@Override
	public <T extends Output> void writeExternal(T out) throws IOException {
		out.writeStartDocument(ELEMENT);
		
		if (_namespaces.size() > 0) {
			for (String prefix : _namespaces.keySet()) {
				out.writeNamespace(prefix,_namespaces.get(prefix));
			}
		}
		
		_documentType.writeExternal(out);
		if (_components != null) {
			out.writeStart(ELEMENT_COMPONENTS);
			for (int i = 0, n = _components.size(); i < n; i++) {
				_components.get(i).writeExternal(out);
			}
			out.writeEnd();
		}
		out.writeEndDocument();
	}
	/**
	 * @see org.akomantoso.core.io.Externalizable#readExternal(org.akomantoso.core.io.Input)
	 */
	@Override
	public <T extends Input> void readExternal(T in) throws IOException {
		
		in.readNamespace(this);

		in.readNextStartElement();
		_documentType = DocumentTypeGroup.instantiate(in.getLocalName());
		_documentType.readExternal(in);
		
		in.readNextStartElement();
		
		if (in.getEventType() == InputConstants.START_ELEMENT && ELEMENT_COMPONENTS == in.getLocalName()) {
			_components = new ArrayList<Component>(4);
			Component component;
			int eventType;
			while (true) {
				eventType = in.readNext();
				switch (eventType) {
				case InputConstants.START_ELEMENT:
					_components.add(component = new Component());
					component.readExternal(in);
					break;
				case InputConstants.END_ELEMENT:
					if ("components".equals(in.getLocalName())) {
						return;
					}
				}
			}
			
		}
		
	}
	public void addNamespace(String namespacePrefix, String namespaceURI) {
		_namespaces.put(namespacePrefix, namespaceURI);
	}
	
}